/**
 * ***************************************************************
 * JADE - Java Agent DEvelopment Framework is a framework to develop multi-agent
 * systems in compliance with the FIPA specifications. Copyright (C) 2000 CSELT
 * S.p.A. * GNU Lesser General Public License
 *
 * This library is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation, version 2.1 of the License. * This library is
 * distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
 * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 * details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this library; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 * ***************************************************************
 */
package BookTrading;

import jade.core.AID;
import jade.core.Agent;
import jade.core.behaviours.*;
import jade.lang.acl.ACLMessage;
import jade.lang.acl.MessageTemplate;
import jade.domain.DFService;
import jade.domain.FIPAException;
import jade.domain.FIPAAgentManagement.DFAgentDescription;
import jade.domain.FIPAAgentManagement.ServiceDescription;
import java.io.IOException;

import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;

public class BookSellerAgent extends Agent {

    // The catalogue of books for sale (maps the title of a book to its price)
    public Hashtable<String, BookObject> catalogue;
    public List<BookObject> listObject = new ArrayList<>();
    // The GUI by means of which the user can add books in the catalogue
    private BookSellerGui myGui;

    public BookObject getFirstItemInCatalogue() {
        BookObject result = new BookObject();
        if (!isNotEmptyCatalogue()) {
            result = (BookObject) catalogue.keySet().toArray()[0];
        }
        return result;
    }

    protected boolean isNotEmptyListObject() {
        if (listObject.size() == 0) {
            return false;
        }
        return true;
    }

    protected boolean isNotEmptyCatalogue() {
        if (catalogue.size() == 0) {
            return false;
        }
        return true;
    }

    // Put agent initializations here
    protected void setup() {
        // Create the catalogue
        catalogue = new Hashtable();

        // Create and show the GUI 
        myGui = new BookSellerGui(this);
        myGui.showGui();

        // Register the book-selling service in the yellow pages
        DFAgentDescription dfd = new DFAgentDescription();
        dfd.setName(getAID());
        ServiceDescription sd = new ServiceDescription();
        sd.setType("book-selling");
        sd.setName("JADE-book-trading-seller");
        dfd.addServices(sd);
        try {
            DFService.register(this, dfd);
        } catch (FIPAException fe) {
            fe.printStackTrace();
        }

       // this.addBehaviour(new SendObjectToEncheres());
    }

    // Put agent clean-up operations here
    protected void takeDown() {
        // Deregister from the yellow pages
        try {
            DFService.deregister(this);
        } catch (FIPAException fe) {
            fe.printStackTrace();
        }
        // Close the GUI
        myGui.dispose();
        // Printout a dismissal message
        System.out.println("Seller-agent " + getAID().getName() + " terminating.");
    }

    //Add new object to list of object
    //Author: NGUYEN TRANG
    //Create date: 26/02/2015
    public void addObjectToListObject(String title, int price) {
        System.out.println("Run function");
        addBehaviour(new OneShotBehaviour() {
            boolean isAddObject = false;
            @Override
            public void action() {
                if (!title.equals("")) {
                    BookObject object = new BookObject(title, price);
                    listObject.add(object);
                    System.out.println("Le vendeur a ajouté :");
                    System.out.println("L'objet " + title + " au prix de " + price + " Euros (€).");
                    System.out.println("à son catalogue. ");
                    isAddObject = true;
                    addBehaviour(new SendObjectToEncheres());
                }
            }

//            @Override
//            public boolean done() {
//                return false ;
//            }
        });

//        if (title != "") {
//            BookObject object = new BookObject(title, price);
//            listObject.add(object);
//            System.out.println("Le vendeur a ajouté :");
//            System.out.println("L'objet " + title + " au prix de " + price + " Euros (€).");
//            System.out.println("à son catalogue. ");
//
//        }
    }

    /**
     * This is invoked by the GUI when the user adds a new book for sale
     */
    public void updateCatalogue(final String title, final int price) {
        addBehaviour(new OneShotBehaviour() {
            public void action() {
                BookObject object = new BookObject(title, price);
                catalogue.put(title, object);
                System.out.println("Le vendeur " + getAID().getLocalName() + " a ajouté :");
                System.out.println("L'objet " + title + " au prix de " + price + " Euros (€).");
                System.out.println("à son catalogue. ");
                // test fonction showCatalogue
                showCatalogue();
            }
        });
    }

    public void showCatalogue() {
        addBehaviour(new OneShotBehaviour() {
            public void action() {
                for (int k = 0; k < catalogue.size(); k++) {
                    ;

                    System.out.println("L'objet " + catalogue.toString());

                }

            }
        });
    }

    /**
     * Inner class OfferRequestsServer. This is the behaviour used by
     * Book-seller agents to serve incoming requests for offer from buyer
     * agents. If the requested book is in the local catalogue the seller agent
     * replies with a PROPOSE message specifying the price. Otherwise a REFUSE
     * message is sent back.
     */
    private class OfferRequestsServer extends CyclicBehaviour {

        @Override
        public void action() {
            MessageTemplate mt = MessageTemplate.MatchPerformative(ACLMessage.CFP);
            ACLMessage msg = myAgent.receive(mt);
            if (msg != null) {
                // CFP Message received. Process it
                String title = msg.getContent();
                //System.out.println("title" + title);
                ACLMessage reply = msg.createReply();

                //Integer price = (Integer) catalogue.get(title);
                BookObject object = (BookObject) catalogue.get(title);
                //System.out.println(object.getName() + object.getPrice());
                //Integer price = object.getPrice();
                if (object != null) {
                    // The requested book is available for sale. Reply with the price
                    reply.setPerformative(ACLMessage.PROPOSE);
                    try {
                        //reply.setContent(String.valueOf(price.intValue()));
                        reply.setContentObject(object);
                        System.out.println("Send object");
                    } catch (IOException ex) {
                        Logger.getLogger(BookSellerAgent.class.getName()).log(Level.SEVERE, null, ex);
                    }
                } else {
                    // The requested book is NOT available for sale.
                    reply.setPerformative(ACLMessage.REFUSE);
                    reply.setContent("not-available");
                }
                myAgent.send(reply);
            } else {
                block();
            }
        }
    }  // End of inner class OfferRequestsServer

    /**
     * Inner class PurchaseOrdersServer. This is the behaviour used by
     * Book-seller agents to serve incoming offer acceptances (i.e. purchase
     * orders) from buyer agents. The seller agent removes the purchased book
     * from its catalogue and replies with an INFORM message to notify the buyer
     * that the purchase has been sucesfully completed.
     */
    private class PurchaseOrdersServer extends CyclicBehaviour {

        public void action() {
            MessageTemplate mt = MessageTemplate.MatchPerformative(ACLMessage.ACCEPT_PROPOSAL);
            ACLMessage msg = myAgent.receive(mt);
            if (msg != null) {
                // ACCEPT_PROPOSAL Message received. Process it
                String title = msg.getContent();
                ACLMessage reply = msg.createReply();

                BookObject object = (BookObject) catalogue.remove(title);
                if (object != null) {
                    reply.setPerformative(ACLMessage.INFORM);
                    System.out.println(title + " sold to agent " + msg.getSender().getName());
                } else {
                    // The requested book has been sold to another buyer in the meanwhile .
                    reply.setPerformative(ACLMessage.FAILURE);
                    reply.setContent("not-available");
                }
                myAgent.send(reply);
            } else {
                block();
            }
        }
    }  // End of inner class OfferRequestsServer

    //Class Behaviour to send Object to EncheresAgent
    //Author: NGUYEN TRANG
    //Create date: 26/02/2015
    private class SendObjectToEncheres extends Behaviour {

        private boolean result = false;

        @Override
        public void action() {
            if (isNotEmptyListObject()) {
                // Update the list of enchere agents
                DFAgentDescription template = new DFAgentDescription();
                ServiceDescription sd = new ServiceDescription();
                sd.setType("object-enchere");
                template.addServices(sd);
                AID enchere = new AID();;
                try {
                    DFAgentDescription[] result = DFService.search(myAgent, template);
                    System.out.println("Found the following enchere agents:");
                    enchere = result[0].getName();
                    System.out.println(enchere.getName());
                } catch (FIPAException fe) {
                    fe.printStackTrace();
                }
                ACLMessage msg = new ACLMessage(ACLMessage.INFORM);
                msg.addReceiver(enchere);
                msg.setLanguage("English");
                BookObject object = (BookObject) listObject.get(0);
                System.out.println(object.getName());
                try {
                    msg.setContentObject(object);
                } catch (IOException ex) {
                    Logger.getLogger(BookSellerAgent.class.getName()).log(Level.SEVERE, null, ex);
                }
                send(msg);
                result = true;
            }
        }

        @Override
        public boolean done() {
            return result;
        }
    }
}
